#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <pthread.h>
#include "cJSON.h"
#define N 64

void commandHandle(char *str, int clifd);
void existsPoint(int clifd, cJSON *root);
void acceptFile(int clifd, cJSON *root);
void heartbeat(int clifd);
void *Reply(void *arg);

int broadfd;

int main(int argc, char const *argv[])
{
    //创建一个socket文件描述符
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (broadfd < 0)
    {
        perror("sock err");
        return -1;
    }

    //绑定套接字(ip+port)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888); //端口号
    addr.sin_addr.s_addr = INADDR_ANY;

    int addrlen = sizeof(addr);
    if (bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }
    pthread_t thread = 0;
    if (pthread_create(&thread, NULL, Reply, NULL) != 0)
    {
        printf("pthread_create error\n");
        return -1;
    }

    //变身为TCP服务器，准备接收软件的升级文件
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("sock err");
        return -1;
    }

    if (bind(tcpfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    //监听套接字
    if (listen(tcpfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }

    //接收客户端的连接
    printf("wait client connect\n");
    //4.循环等待客户端连接并创建进程
    pid_t pid;
    int clifd;
    while (1)
    {
        clifd = accept(tcpfd, NULL, NULL);
        if (accept < 0)
        {
            perror("accept err");
            continue;
        }
        pid = fork();
        if (pid < 0)
        {
            perror("fock err");
            return -1;
        }
        else if (pid == 0)
        {
            ssize_t s;
            char buf[128] = "";
            //子进程用不到sockfd
            close(tcpfd);
            //循环接受信息
            while (1)
            {

                s = recv(clifd, &buf, sizeof(buf), 0);
                if (s < 0)
                {
                    return -1;
                }
                else if (s == 0)
                {
                    printf("\n");
                    exit(-1); //不能是break
                }
                else
                {
                    //在此处解析json
                    commandHandle(buf, clifd);
                    printf("%s\n", buf);
                }
            }
        }
        close(clifd);
    }
    printf("new cononect coming\n");
    return 0;
}

void commandHandle(char *str, int clifd)
{
    cJSON *root = NULL;
    cJSON *temp = NULL;

    root = cJSON_Parse(str);
    if (root == NULL)
    {
        printf("json解析失败，可能不是json字符串");
        return;
    }
    temp = cJSON_GetObjectItem(root, "type");
    if (temp == NULL)
    {
        printf("json中type获取失败-data\n");
    }
    else if (temp->valueint == 1) //确认点表是否存在
    {
        printf("解析为确认点表是否存在指令\n");
        existsPoint(clifd, root);
    }
    else if (temp->valueint == 2) //进入文件带接受状态
    {
        printf("解析为进入文件带接受状态指令\n");
        acceptFile(clifd, root);
    }
    else if (temp->valueint == 3) //心跳包
    {
        printf("心跳包指令\n");
        heartbeat(clifd);
    }
    cJSON_Delete(root);
}

//确认是否需要重发点表
void existsPoint(int clifd, cJSON *root)
{
    //解析cJSON，确认是否发消息，回复发消息 《---任务
    //回复心跳包消息 《---任务

    char *str;
    char buf[4096] = "";

    FILE *fd = NULL;
    if ((fd = fopen("/mnt/config/dev_config123.json", "rw")) == NULL)
    {
        cJSON_AddBoolToObject(root, "up_config", 1);
        perror("fopen error");
    }
    else if (fread(buf, 4096, 1, fd) != 0)
    {
        cJSON_AddNumberToObject(root, "result", 1);
        printf("fread error\n");
    }
    else
    {
        //判断是否能解析成功，版本，确定是否需要下发
        cJSON *temp = cJSON_CreateObject(); //创建主对象
        temp = cJSON_Parse(buf);
        if(temp == NULL)
        {
            cJSON_AddBoolToObject(root, "up_config", 1);
        }
        

        cJSON *array = cJSON_CreateArray(); //创建数组
        cJSON_AddItemToObject(root, "data", array);
        cJSON_AddItemToObject(array, "NULL", temp);
    }
    cJSON_AddNumberToObject(root, "result", 0);
    cJSON_AddBoolToObject(root, "up_config", 0);
    str = cJSON_Print(root);
    send(clifd, str, strlen(str), 0);
    free(str);
}

//进入
void acceptFile(int clifd, cJSON *root)
{
    //解析cJSON，进入待接受状态，发消息《---任务
    //回复心跳包消息 《---任务
    char *str;
    char filename[32];
    int filelen = 0;

    cJSON *temp = cJSON_GetObjectItem(root, "data");
    cJSON *msg = cJSON_GetObjectItem(temp, "flag");

    if (strcmp(msg->valuestring, "start") != 0)
    {
        printf("不是开始\n");
        return;
    }

    msg = cJSON_GetObjectItem(temp, "file_name");
    strcpy(filename, msg->valuestring);
    msg = cJSON_GetObjectItem(temp, "file_len");
    filelen = msg->valueint;

    cJSON_DeleteItemFromObject(temp, "file_name");
    cJSON_DeleteItemFromObject(temp, "file_len");
    //发送准备开始
    printf("发送准备开始信息\n");
    str = cJSON_Print(root);
    send(clifd, str, strlen(str), 0);
    free(str);
    //接受数据
    printf("准备接受数据\n");
    int i = 0;
    char buf[4096];
    FILE *fd = NULL;
    
    if ((fd = fopen(filename, "w+")) == NULL)
    {
        perror("fopen write error");
    }

    while (i < filelen)
    {
        i += recv(clifd, &buf, sizeof(buf), 0);
        fwrite(buf, strlen(buf), 1, fd);
    }
    printf("write ok\n");
    
    //接收判断
    recv(clifd, &buf, sizeof(buf), 0);
    //if(strcmp(buf,""))

    

    cJSON_DeleteItemFromObject(temp, "flag");
    cJSON_AddStringToObject(temp, "flag", "stop");
    str = cJSON_Print(root);
    send(clifd, str, strlen(str), 0);
    free(str);
}

//心跳包处理
void heartbeat(int clifd)
{
    //回复心跳包消息 《---任务
    char *str;
    cJSON *root = cJSON_CreateObject(); //创建主对象
    cJSON_AddNumberToObject(root, "type", 3);
    cJSON_AddNumberToObject(root, "result", 0);

    str = cJSON_Print(root);
    send(clifd, str, strlen(str), 0);
    free(str);
    cJSON_Delete(root);
}

void *Reply(void *arg)
{
    ssize_t len;
    ssize_t addrlen = sizeof(struct sockaddr_in);
    char buf[N] = {0};
    struct sockaddr_in cliaddr;
    cliaddr.sin_addr.s_addr = 0;
    cliaddr.sin_port = 0;
    //接收"coffee"搜索包
    while (1)
    {
        bzero(buf, N);
        len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
        //判断是否是本公司产品：收到的数据是否"coffee"
        if (strcmp(buf, "coffee") != 0)
        {
            printf("not my coffee\n");
            return NULL;
        }
        printf("my coffee\n");

        //回复yes，告诉软件，我收到了搜索协议，并且回复地址
        printf("%d  %d  %d %d\n",cliaddr.sin_addr.s_addr,cliaddr.sin_port,inet_addr("192.168.0.119"),8888);
        cliaddr.sin_port = htons(8888);
        sendto(broadfd, "yes", sizeof("yes"), 0, (struct sockaddr *)&cliaddr, addrlen);
    }
}